/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.tabbedproperties.composite;

import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.umlutils.Element;

/**
 * Base class for a complex section composite. This composite has a label, a
 * table that describes a tree structure, and four buttons on the side of the
 * table to add an element into the table, remove selected element(s), move up
 * or down the selected element.
 * 
 * @author Remi SCHNEKENBURGER
 */
public abstract class DecoratedTableComposite implements ISectionComposite {

	/**
	 * Image for the add element button.
	 */
	final protected static Image NEW_ELEMENT_IMG = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Add_16x16.gif");
	
	/**
	 * Image for the delete element button.
	 */
	final protected static Image DELETE_ELEMENT_IMG = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Delete_16x16.gif");
	
	/**
	 * Image for the up button.
	 */
	final protected static Image UP_ELEMENT_IMG = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"ArrowUp_16x16.gif");
	
	/**
	 * Image for the down button.
	 */
	final protected static Image DOWN_ELEMENT_IMG = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"ArrowDown_16x16.gif");

	// child composites for the table composite
	
	/**
	 * main composite of this complex composite.
	 */
	protected Composite composite;
	
	/**
	 * Label above the table.
	 */
	protected CLabel label;
	
	/**
	 * Table that displays a property for the current element.
	 */
	protected Table table;
	
	/**
	 * Button that adds an element.
	 */ 
	protected Button addButton;
	
	/**
	 * Button that removes an element.
	 */ 
	protected Button removeButton;
	
	/**
	 * button that moves the element up.
	 */
	protected Button upButton;
	
	/**
	 * button that moves the element down.
	 */
	protected Button downButton;
	
	// listeners for buttons
	/**
	 * Listener for the add button.
	 */
	protected MouseListener addButtonlistener;
	
	/**
	 * Listener for the delete button.
	 */
	protected MouseListener removeButtonlistener;
	
	/**
	 * Listener for the up button.
	 */
	protected MouseListener upButtonlistener;
	
	/**
	 * Listener for the down button.
	 */
	protected MouseListener downButtonlistener;
	
	/**
	 * 
	 */
	protected Listener tableListener;
	
	/**
	 * Element selected in the Papyrus modeler.
	 */
	protected Element element;
	
	
	// Construction parameters for the composite
	/**
	 * text of the label.
	 */
	protected String name;
	
	/**
	 * returns the element that is selected in Papyrus tool, for which
	 * properties are displayed in the property section.
	 * 
	 * @return the element
	 */
	public Element getElement() {
		return element;
	}

	/**
	 * Sets the element that holds property displyed in property section.
	 * 
	 * @param element the element to set
	 */
	public void setElement(Element element) {
		this.element = element;
	}
	
	/**
	 * Constructor.
	 * 
	 * @param name text of the Label on the top left of this composite
	 */
	public DecoratedTableComposite(String name) {
		this.name = name;
		this.addButtonlistener = new AddButtonlistener();
		this.removeButtonlistener = new RemoveButtonlistener();
		this.upButtonlistener = new UpButtonlistener();
		this.downButtonlistener = new DownButtonlistener();
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.ISectionComposite#createContent(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory)
	 */
	/**
	 * 
	 * 
	 * @param factory 
	 * @param parent 
	 * 
	 * @return 
	 */
	public Composite createContent(Composite parent,
			TabbedPropertySheetWidgetFactory factory) {
		composite = factory.createFlatFormComposite(parent);

		FormData data;

		/////////////////////////////////////////////////////////////////////////////
		// Create and place button vertically on the left side
		// Button : Add Element
		// Button Delete Element
		removeButton = factory.createButton(composite, "",  SWT.PUSH);
		removeButton.setVisible(true);
		removeButton.setImage(DELETE_ELEMENT_IMG);
		removeButton.setToolTipText("Delete selected element(s)");
		data = new FormData();
		// data.top   = new FormAttachment(addButton, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, 0);
		data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE);
		removeButton.setLayoutData(data);
		removeButton.addMouseListener(removeButtonlistener);
		
		addButton = factory.createButton(composite, "", SWT.PUSH);
		addButton.setVisible(true);
		addButton.setImage(NEW_ELEMENT_IMG);
		addButton.setToolTipText("Add a new element");
		
		data = new FormData();
		// data.top   = new FormAttachment(label, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, 0);
		data.right = new FormAttachment(removeButton, -ITabbedPropertyConstants.HSPACE);
		addButton.setLayoutData(data);
		addButton.addMouseListener(addButtonlistener);

		// Button Up
		upButton = factory.createButton(composite, "", SWT.PUSH);
		upButton.setVisible(true);
		upButton.setImage(UP_ELEMENT_IMG);
		upButton.setToolTipText("Up");

		data = new FormData();
		// data.top   = new FormAttachment(removeButton, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, 0);
		data.right = new FormAttachment(addButton, -ITabbedPropertyConstants.HSPACE);
		upButton.setLayoutData(data);
		upButton.addMouseListener(upButtonlistener);
		
		
		// Button Down
		downButton = factory.createButton(composite, "", SWT.PUSH);
		downButton.setVisible(true);
		downButton.setImage(DOWN_ELEMENT_IMG);
		downButton.setToolTipText("Down");

		data = new FormData();
		// data.top   = new FormAttachment(upButton, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, 0);
		data.right = new FormAttachment(upButton, -ITabbedPropertyConstants.HSPACE);
		downButton.setLayoutData(data);
		downButton.addMouseListener(downButtonlistener);
		
		// Create label
		label = factory.createCLabel(composite, name+":", SWT.NONE);
		label.setLayout(new FormLayout());
		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.right = new FormAttachment(downButton, -ITabbedPropertyConstants.HSPACE-50);
		data.top  = new FormAttachment(0, 0);
		label.setLayoutData(data);
		
		/////////////////////////////////////////////////////////////////////////////
		// Create and place Table
		table = factory.createTable(composite, SWT.MULTI | SWT.H_SCROLL | SWT.BORDER);
		table.setLayout(new FormLayout());
		table.setVisible(true);
		table.addListener(SWT.MouseDoubleClick, tableListener = new EditItemListener());

		data = new FormData();
		data.height = 100;
		data.top    = new FormAttachment(label, ITabbedPropertyConstants.VSPACE);
		data.left   = new FormAttachment(0 , ITabbedPropertyConstants.HSPACE);
		data.right  = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE);

		table.setLayoutData(data);
		return composite;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.composites.ISectionComposite#refresh()
	 */
	/**
	 * 
	 */
	public void refresh() {
	}
	
	/**
	 * Sets the layout data to the main composite of this complex element.
	 * 
	 * @param data the new LayoutData
	 */
	public void setLayoutData(Object data) {
		composite.setLayoutData(data);
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public Composite getMainComposite() {
		return composite;
	}
		
	/**
	 * Returns the current Editor.
	 * 
	 * @return the current editor
	 */
	public IEditorPart getActiveEditor() {
		return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); 
	}
	
	/**
	 * Returns the model manager associated to the current active editor.
	 * @return the current model manager or <code>null</code>
	 */
	public ModelManager getModelManager() {
		return (ModelManager)getActiveEditor().getAdapter(ModelManager.class);
	}
	
	/**
	 * Returns the label provider for the composite
	 * @return the label provider or <code>null</code>
	 */
	public AdapterFactoryLabelProvider getLabelProvider() {
		final ModelManager modelManager = getModelManager();
		if(modelManager!=null) {
			return modelManager.getLabelProvider();
		}
		return null;
	}
	
	/**
	 * action executed when the add button is pressed.
	 */
	public void addButtonPressed() {
	}
	
	/**
	 * action executed when the remove button is pressed.
	 */
	public abstract void removeButtonPressed();
	
	/**
	 * action executed when the up button is pressed.
	 */
	public abstract void upButtonPressed();
	
	/**
	 * action executed when the down button is pressed.
	 */
	public abstract void downButtonPressed();
	
	/**
	 * action executed when a table item is edited.
	 * 
	 * @param item 
	 */
	public abstract void editItem(TableItem item);
	
	/**
	 * Listener for the Add Button
	 * Specific behavior is implemented in {@link DecoratedTableComposite#addButtonPressed()}.
	 * 
	 * @author Remi SCHNEKENBURGER
	 */
	private class AddButtonlistener implements MouseListener {
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDoubleClick(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDown(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseUp(MouseEvent e) {
			addButtonPressed();
			refresh();
		}
	}

	/**
	 * Listener for the Remove Button
	 * Specific behavior is implemented in {@link DecoratedTableComposite#removeButtonPressed()}.
	 * 
	 * @author Remi SCHNEKENBURGER
	 */
	private class RemoveButtonlistener implements MouseListener {
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDoubleClick(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDown(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseUp(MouseEvent e) {
			removeButtonPressed();
			refresh();
		}
	}

	/**
	 * Listener for the Up Button
	 * Specific behavior is implemented in {@link DecoratedTableComposite#upButtonPressed()}.
	 * 
	 * @author Remi SCHNEKENBURGER
	 */
	private class UpButtonlistener implements MouseListener {
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDoubleClick(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDown(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseUp(MouseEvent e) {
			TableItem[] tableItems = table.getSelection();
			upButtonPressed();
			refresh();
			// Keep selection
			table.setSelection(tableItems);
		}
	}

	/**
	 * Listener for the Down Button
	 * Specific behavior is implemented in {@link DecoratedTableComposite#downButtonPressed()}.
	 * 
	 * @author Remi SCHNEKENBURGER
	 */
	private class DownButtonlistener implements MouseListener {
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDoubleClick(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseDown(MouseEvent e) {
			// do nothing
		}
		
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void mouseUp(MouseEvent e) {
			TableItem[] tableItems = table.getSelection();
			downButtonPressed();
			refresh();
			// Keep selection
			table.setSelection(tableItems);
		}
	}
	
	/**
	 * 
	 */
	private class EditItemListener implements Listener {
		
		/** @{inheritDoc} */
		public void handleEvent(Event event) {
			if(table.getSelection().length > 0) {
				TableItem item = table.getSelection()[0];
				editItem(item);
			}
		}
	}
	
	/**
	 * removes listeners from buttons.
	 */
	public void dispose() {
		if(addButton!=null && !addButton.isDisposed())
			addButton.removeMouseListener(addButtonlistener);
		if(removeButton!=null && !removeButton.isDisposed())
			removeButton.removeMouseListener(removeButtonlistener);
		if(upButton!=null && !upButton.isDisposed())
			upButton.removeMouseListener(upButtonlistener);
		if(downButton!=null && !downButton.isDisposed())
			downButton.removeMouseListener(downButtonlistener);
		if(table!=null && !table.isDisposed())
			table.removeListener(SWT.MouseDoubleClick, tableListener);
	}
}
